package com.zhoukai.manage.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SmUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhoukai.manage.converter.LicenseConverter;
import com.zhoukai.manage.dto.LicenseContentDTO;
import com.zhoukai.manage.form.LicenseCreateForm;
import com.zhoukai.manage.util.EncryptUtil;
import com.zhoukai.manage.util.HttpServletWrite;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Map;

/**
 * 认证证书生成
 */
@RestController
@Slf4j
public class LicenseController {

    /**
     * 生成密钥
     */
    @PostMapping(value = "/license/secretKey")
    public void secretKeyCreate(HttpServletResponse response) throws Exception {
        Map<String, String> keyMap = null;
        try {
            keyMap = EncryptUtil.initGenerateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            log.error("生成密钥异常", e);
            HttpServletWrite.writeText(response, "生成密钥异常");
            return;
        }
        HttpServletWrite.writeJson(response, JSON.toJSONString(keyMap));
    }

    /**
     * 生成证书
     */
    @PostMapping(value = "/license/create")
    public void licenseCreate(@RequestBody @Valid LicenseCreateForm form, HttpServletResponse response) throws Exception {
        String encryptedContent = null;
        try {
            checkTime(form);
            //公钥
            String publicKeyString = form.getSecretKey();

            // 生成签名
            LicenseContentDTO licenseContent = LicenseConverter.INSTANCE.createForm2Dto(form);
            licenseContent.setCreateTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            licenseContent.setSign(EncryptUtil.encryptByPublicKey(sign(JSON.toJSONString(licenseContent)), publicKeyString));

            // 生成加密内容
            encryptedContent = EncryptUtil.encryptByPublicKey(JSON.toJSONString(licenseContent), publicKeyString);
        } catch (Exception e) {
            HttpServletWrite.writeText(response, e.getMessage());
            return;
        }

        response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("license.lic", "UTF-8"));
        response.setContentType("application/octet-stream;charset=UTF-8");
        //创建输出流
        ServletOutputStream sot = response.getOutputStream();
        sot.write(encryptedContent.getBytes(StandardCharsets.UTF_8));
        //关闭流
        sot.close();
    }

    private void checkTime(LicenseCreateForm form) {
        Date now = new Date();
        Date issuedTime = null;
        try {
            issuedTime = DateUtil.parse(form.getIssuedTime(), "yyyy-MM-dd HH:mm:ss");
        } catch (Exception e) {
            throw new RuntimeException("证书生效时间格式异常(yyyy-MM-dd HH:mm:ss)");
        }
        Date expiryTime = null;
        try {
            expiryTime = DateUtil.parse(form.getExpiryTime(), "yyyy-MM-dd HH:mm:ss");
        } catch (Exception e) {
            throw new RuntimeException("证书失效时间格式异常(yyyy-MM-dd HH:mm:ss)");
        }
        if (now.after(expiryTime)) {
            throw new RuntimeException("证书失效时间不能早于当前时间");
        }
        if (expiryTime.before(issuedTime)) {
            throw new RuntimeException("证书生效时间不能晚于证书失效时间");
        }
    }

    /**
     * 验证证书
     */
    @PostMapping(value = "/license/check")
    public void licenseCheck(@RequestParam("file") MultipartFile file
            , @RequestParam("secretKey") String secretKey
            , HttpServletResponse response) throws Exception {
        // 解密
        String decryptContent = null;

        try {
            // 获取文件内容
            InputStream inputStream = file.getInputStream();
            byte[] bytes = IoUtil.readBytes(inputStream);
            String encryptedContent = new String(bytes, StandardCharsets.UTF_8);

            // 解密
            decryptContent = EncryptUtil.decryptByPrivateKey(encryptedContent, secretKey);

            // 校验内容
            LicenseContentDTO licenseContent = JSON.parseObject(decryptContent, LicenseContentDTO.class);
            String licenseSign = EncryptUtil.decryptByPrivateKey(licenseContent.getSign(), secretKey);


            licenseContent.setSign(null);
            String checkSignContent = sign(JSON.toJSONString(licenseContent));
            if (!licenseSign.equals(checkSignContent)) {
                HttpServletWrite.writeText(response, "证书错误");
                return;
            }
        } catch (Exception e) {
            log.error("认证证书校验异常", e);
            HttpServletWrite.writeText(response, "证书错误");
            return;
        }
        HttpServletWrite.writeJson(response, decryptContent);
    }

    private String sign(String content) {
        String jsonString = JSON.toJSONString(JSON.parseObject(content), SerializerFeature.MapSortField);
        return SmUtil.sm3(jsonString);
    }

}
